跳到主要内容

TypeScript 写一个事件管理器

编写一个单例的基类

因为一般 EventMananger 是全局管理器,所以这里做一个单例基类

export default class Singleton{
static getInstance<T extends {}>(this: new () => T): T {
if(!(<any>this).instance){
(<any>this).instance = new this();
}
return (<any>this).instance;
}
}

编写一个承载数据的事件基类

import { EventID } from './EventID'
import EventMananger from './EventManager'

/**
* 传输事件的基本单元,如果想要传输更多不一样的数据需要自己再实例一个对象
*/
export default class EventData<T> {
public eid: EventID
private _data: T | null

/**
* 这里使用 private 修饰,避免用户直接创建这个对象
* @param eid 当前事件的类型
*/
private constructor(eid: EventID) {
this.eid = eid
this._data = null;
}

public Send(arg: T): void {
this._data = arg;
EventMananger.getInstance().SendEvent(this)
}

public get data() {
return this._data;
}

public static CreateEvent<T>(eventId: EventID): EventData<T> {
return new EventData<T>(eventId)
}
}

编写一个观察者接口

import EventData from "./EventData";

/**
* 事件监听者基类
*/
export default interface IEventObserver {
HandleEvent<T>( resp: EventData<T>):void
}

编写管理器

导入集合工具类:

npm install typescript-collections --save

注意:要把 tsconfig 里面的这个改一下

"moduleResolution": "node"

下面是代码

import * as Collections from 'typescript-collections';
import Singleton from '../Singleton'
import EventData from './EventData'
import { EventID } from './EventID'
import IEventObserver from './IEventObserver'

export default class EventManager extends Singleton {
// 维护一个观察者队列
private observerList: Collections.Dictionary<EventID, Collections.LinkedList<IEventObserver>> =
new Collections.Dictionary<EventID,Collections.LinkedList<IEventObserver>>()

//private readonly eventQueue:Collections.Queue<EventData> = new Collections.Queue<EventData>(); //消息队列

/**
* 发送事件
* @type 事件类型
* @args 携带数据
*/
public SendEvent<T>(eve: EventData<T>) {
// 如果没有观察者监听这个事件则结束
if (!this.observerList.containsKey(eve.eid)) return

// 通知监听了这个事件的全部观察者
let observers = this.observerList.getValue(eve.eid)
observers?.forEach((x) => {
if (x != null) {
x.HandleEvent(eve)
}
})
}

/**
* 注册一个监听者
* @param newobj 需要注册的监听者
* @param eid 需要监听的事件 ID
*/
private RegisterObj(newobj: IEventObserver, eid: EventID): void {
if (!this.observerList.containsKey(eid)) {
let list = new Collections.LinkedList<IEventObserver>()
list.add(newobj)
this.observerList.setValue(eid, list)
} else {
let list = this.observerList.getValue(eid)
// 不存在才要添加
if (list != null && !list.contains(newobj)) {
list.add(newobj);
}
}
}

/**
* 监听者在这里注册,注意这里形参是可变参数
* @param newobj 需要被注册的监听者
* @param eids 需要监听的事件列表
* @returns
*/
public static Register(newobj: IEventObserver, ...eids: EventID[]): void {
for (const eid of eids) {
EventManager.getInstance().RegisterObj(newobj, eid)
}
}

/**
* 移除监听者
* @param removeObj 需要移除的监听对象
*/
public RemoveObj(removeObj: IEventObserver): void {
this.observerList.forEach((k, v) => {
let list = v
list.remove(removeObj)
})
}

/**
* 移除一个监听者
* @param removeObj 需要移除的对象
* @returns
*/
public static Remove(removeObj: IEventObserver): void {
console.log(`销毁了 ${removeObj}`);

EventManager.getInstance().RemoveObj(removeObj)
}
}

在 Vue3 中使用测试

import EventManager from '../ts/util/EventTools/EventManager'
import IEventObserver from '../ts/util/EventTools/IEventObserver'
import EventData from '../ts/util/EventTools/EventData'
import { EventID } from '../ts/util/EventTools/EventID'

class Test implements IEventObserver {
constructor() {
EventManager.Register(this, EventID.TEST)
}

HandleEvent<T>(resp: EventData<T>): void {
console.log('执行了')
console.log(resp)
}
}

let temp = new Test()

export default {
name: 'HelloWorld',
props: {
msg: String
},
data() {
return {
count: 0
}
},
setup() {
const INIT_OPTIONS = {
width: 640,
height: 480,
color: "#00FF00",
label: "VGA",
};

// 这里使用 typeof 快速匹配类型
let event = EventData.CreateEvent<typeof INIT_OPTIONS>(EventID.TEST)

return {
onclick: () => {
event.Send(INIT_OPTIONS)
}
}
},
// 要在生命周期结束时销毁,否则会导致内存泄漏(因为在 EventManager 中一直被引用着,没有释放)
beforeUnmount() {
EventManager.Remove(temp);
}
}